#ifndef SLOT_H
#define SLOT_H

#include <vector>
#include "../element.h"

class AbstractDelegate;

/*!
 *	\class AbstractSlot()
 * 	\brief	Classe virtuelle pure utilisé uniquement dans le but de permettre le polymorphisme et ainsi de stocker plusieurs
 * 			objets de type Slot différent dans un vector std
 */
 
class AbstractSlot
{
    public:

    AbstractDelegate * abstractDelegate;
	
	/*!
	 * 	\fn virtual void Run()=0;
	 * 	\brief	Méthode virtuelle pure utilisé pour représenter la méthode qui exécute la fonction slot
         */

    virtual void Run()=0;

};


/*!	
 *  \class Slot
 *  \brief Représente un slot, à savoir une méthode membre d'un objet, ainsi que l'objet en question, utilisé conjointement avec un délégué
 */

class Slot : public AbstractSlot
{
    public :

    Element * objetSlot;                /*!< Objet devant éxécuté la méthode membre associé	         */
    int (Element::*pSlot)();            /*!< Prototype du pointeur de la fonction membre à exécuter  */

    Slot(int (Element::*apSlot)(),Element * ref);
    void Run();
};

template <class T>
class Slot1 : public AbstractSlot
{
    public :

    Element * objetSlot;
    int (Element::*pSlot)(T);

    T arg1;

    Slot1(int (Element::*aPslot)(T), Element * ref);

    void AddArgument(T a);
};


template <class T, class U>
class Slot2 : public AbstractSlot
{
    public :

    Element * objetSlot;
    int (Element::*pSlot)(T, U);

    T arg1;
    U arg2;

    Slot2(int (Element::*aPslot)(T, U), Element * ref);

    void AddArguments(T a, U b);
};

Slot::Slot(int (Element::*apSlot)(),Element * ref)
{
        pSlot=apSlot;
        objetSlot=ref;
}

template <class T>
Slot1<T>::Slot1(int (Element::*apSlot)(T),Element * ref)
{
        pSlot=apSlot;
        objetSlot=ref;
}

template <class T>
void Slot1<T>::AddArgument(T a)
{
    arg1=a;
}

template <class T, class U>
Slot2<T,U>::Slot2(int (Element::*aPslot)(T, U), Element *ref)
{
    pSlot=aPslot;
    objetSlot=ref;
}

template<class T, class U>
void Slot2<T,U>::AddARGUMENT(T a, U b)
{
    arg1=a;
    arg2=b;
}

template <class T>
Slot<T>::Slot(int (Element::*apSlot)(void *, void *),Element * ref)
{
        pSlot3=apSlot;
        objetSlot=ref;
        nbArguments=2;
}

template <class T>
Slot<T>::Slot(int (Element::*apSlot)(void *, void *, void *),Element * ref)
{
        pSlot4=apSlot;
        objetSlot=ref;
        nbArguments=3;
}


template <class U>
void AbstractSlot::AddArgument(U aArg1)
{
    arg1=aArg1;
}


template <class U, class V>
void AbstractSlot::AddArgument(U aArg1, V aArg2)
{
    arg1=aArg1;
    arg2=aArg2;
}


template <class U, class V, class W>
void AbstractSlot::AddArgument(U aArg1, V aArg2, W aArg3)
{
    arg1=aArg1;
    arg2=aArg2;
    arg3=aArg3;
}

void Slot::Run()
{
    (objetSlot->*pSlot1)();
}

#endif
